package com.smartcommunity.service.vidInfo.impl;

import com.alibaba.fastjson.JSON;
import com.smartcommunity.api.device.DeviceApi;
import com.smartcommunity.bean.entity.Camera;
import com.smartcommunity.bean.model.Pager;
import com.smartcommunity.elasticsearch.base.impl.BasedataDataService;
import com.smartcommunity.entity.people.RealPeopleHouse;
import com.smartcommunity.es.common.EsBasedataEnum;
import com.smartcommunity.es.common.EsIndex;
import com.smartcommunity.es.common.EsRestUtils;
import com.smartcommunity.entity.people.People;
import com.smartcommunity.entity.vid.SearchModel;
import com.smartcommunity.entity.vid.VidInfo;
import com.smartcommunity.entity.vid.VidInfoModel;
import com.smartcommunity.service.people.impl.PeopleServiceImpl;
import com.smartcommunity.service.vidInfo.VidInfoService;
import com.smartcommunity.utils.BeanMapUtil;
import com.smartcommunity.utils.DateUtils;
import com.smartcommunity.utils.StringUtils;
import com.smartcommunity.utils.VidUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class VidInfoServiceImpl implements VidInfoService {

    @Autowired
    private EsRestUtils eSRestUtils;
    @Autowired
    private DeviceApi deviceApi;
    @Autowired
    private PeopleServiceImpl peopleService;
    @Autowired
    private BasedataDataService basedataDataService;

    @Override
    public Pager<VidInfoModel> listPage(SearchModel searchModel) {
        BoolQueryBuilder boolQueryBuilder = getMustQueryBuilder(searchModel);

        if (searchModel.getText() != null) {
        	boolean isVid = false;
            String vid = searchModel.getText().trim();
            if (vid.contains(",")) {
                boolQueryBuilder.must(QueryBuilders.termsQuery("vid", vid.split(",")));
                isVid = true;
            } else {
                if (VidUtils.isVid(vid)) {
                    boolQueryBuilder.must(QueryBuilders.termsQuery("vid", vid));
                    isVid = true;
                } else {
                    if (VidUtils.isHalfVid(vid)) {
                        boolQueryBuilder.must(QueryBuilders.wildcardQuery("vid", "*" + vid + "*"));
                        isVid = true;
                    }
                }
            }
            if(!isVid) {
            	return new Pager<>();
            }
        }

        boolQueryBuilder = getBoolQueryBuilder(searchModel, boolQueryBuilder);

        //默认降序
        if (StringUtils.isEmpty(searchModel.getSortField())) {
            searchModel.setSortField("lastLogTime");
            searchModel.setSortMode("desc");
        }
        SortBuilder sortBuilder = eSRestUtils.builderSort(searchModel.getSortField(), searchModel.getSortMode());
        try {
            String[] indexs = new String[]{EsIndex.VIDINFO};
            List<Map<String, Object>> results = eSRestUtils.page(indexs, boolQueryBuilder, null, searchModel.getPage(), searchModel.getPageSize(), sortBuilder);
            int total = eSRestUtils.getTotalRecords(indexs, boolQueryBuilder).intValue();
            List<VidInfoModel> vidInfoModelList = buildPeople(results,searchModel.getPage(), searchModel.getPageSize());
            return new Pager<>(searchModel.getPage(), searchModel.getPageSize(), total, vidInfoModelList);
        } catch (Exception e) {
            log.error("视屏档案查询错误", e);
        }
        return new Pager<>();
    }

    @Override
    public List<VidInfo> listVidInfo(SearchModel searchModel) {
        BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(searchModel);
        SortBuilder sortBuilder = eSRestUtils.builderSort(searchModel.getSortField(), searchModel.getSortMode());
        try {
            String[] indexs = new String[]{EsIndex.VIDINFO};
            List<Map<String, Object>> results = eSRestUtils.page(indexs, boolQueryBuilder, null, searchModel.getPage(), searchModel.getPageSize(), sortBuilder);
            List<VidInfo> list = new ArrayList<>();
            if (results != null && results.size() > 0) {
                for (Map<String, Object> map : results) {
                    VidInfo v = bulidVidInfo(map);
                    list.add(v);
                }
            }
            if (!CollectionUtils.isEmpty(list)) {
                Set<String> cameraIds = list.stream().map(VidInfo::getLastCameraId).collect(Collectors.toSet());
                if (!CollectionUtils.isEmpty(cameraIds)) {
                    try {
                        //查询相机信息
                        Map<String, Object> cameraSearchParam = new HashMap<>();
                        cameraSearchParam.put("deviceIds", String.join(",", cameraIds));
                        List<Camera> cameraList = deviceApi.getCameraList(cameraSearchParam).getData();
                        //改map集合
                        Map<String, Camera> cameraMap = BeanMapUtil.mapBean(cameraList, "cameraId");
                        for (VidInfo vidInfo : list) {
                            //设置摄像机信息
                            if (!CollectionUtils.isEmpty(cameraMap) && cameraMap.containsKey(vidInfo.getLastCameraId())) {
                                Camera camera = cameraMap.get(vidInfo.getLastCameraId());
                                vidInfo.setCameraName(camera.getName());
                                vidInfo.setLon(camera.getLon());
                                vidInfo.setLat(camera.getLat());
                            }
                        }
                    } catch (Exception e1) {
                        log.error("视屏档案查询设备信息错误", e1);
                    }
                }
            }
            return list;
        } catch (Exception e) {
            log.error("视屏档案查询错误", e);
        }
        return new ArrayList<>();
    }

    private void buildAddress(List<People> entryList) {
        //如果人员存在多个小区，这里只显示一个小区的信息
        for (People peo : entryList) {
            if(org.apache.commons.collections.CollectionUtils.isNotEmpty(peo.getDetailAddress())) {
                for(RealPeopleHouse realPeopleHouse : peo.getDetailAddress()) {
                        peo.setVillageCode(realPeopleHouse.getVillageCode());
                        peo.setBuildingNo(realPeopleHouse.getBuildingNo());
                        peo.setUnitNo(realPeopleHouse.getUnitNo());
                        peo.setHouseNo(realPeopleHouse.getHouseNo());
                        peo.setResidenceAddress(realPeopleHouse.getDetailAddress());
                        //填充迁出状态，跟随小区的状态
                        peo.setIsLeave(realPeopleHouse.getMove());
                        break;
                }
            }
        }
    }

    private List<VidInfoModel> buildPeople(List<Map<String, Object>> results, int pageNum, int pageSize) {
        List<VidInfoModel> listModel = new ArrayList<>();
        if (results != null && results.size() > 0) {
            String ids = "";
            List<VidInfo> list = new ArrayList<>();
            Set<String> cameraIds = new HashSet<>();
            for (Map<String, Object> map : results) {
                VidInfo v = bulidVidInfo(map);
                if (v != null) {
                    list.add(v);
                    if ("".equals(ids)) {
                        ids = v.getVid();
                    } else {
                        ids = ids + "," + v.getVid();
                    }
                    cameraIds.add(v.getLastCameraId());
                }
            }
            Map<String, Camera> cameraMap = null;
            try {//查询相机信息
                Map<String, Object> cameraSearchParam = new HashMap<>();
                cameraSearchParam.put("deviceIds", String.join(",", cameraIds));
                List<Camera> cameraList = deviceApi.getCameraList(cameraSearchParam).getData();
                //改map集合
                cameraMap = BeanMapUtil.mapBean(cameraList, "cameraId");
            } catch (Exception e1) {
                log.error("视屏档案查询设备信息错误", e1);
            }

            List<People> peopleList = new ArrayList<>();
            if (!StringUtils.isEmpty(ids)) {
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("dataType", EsBasedataEnum.PEOPLE.getIntValue()));
                boolQueryBuilder.must(QueryBuilders.termsQuery("vid", ids.split(",")));
                String[] indexName = new String[] {basedataDataService.getIndexName(null)};

                //查人口的页码固定1从头查询，不能随着视频档案的页码来查询
                pageNum = 1;
                Map<String, Object> result = basedataDataService.page(indexName, boolQueryBuilder, null, pageNum, pageSize, null);
                if(result!=null && result.containsKey("total") && result.containsKey("rows")) {
                    List<Map<String, Object>> rows = (List<Map<String, Object>>) result.get("rows");
                    if (!CollectionUtils.isEmpty(rows)) {
                        rows.forEach(item->{
                            peopleList.add(JSON.parseObject(JSON.toJSONString(item), People.class));
                        });
                        //构建小区住址信息
                        buildAddress(peopleList);
                    }
                }
            }
            if (!CollectionUtils.isEmpty(list)) {
                for (VidInfo vidInfo : list) {
                    VidInfoModel model = new VidInfoModel();
                    //设置摄像机信息
                    if (!CollectionUtils.isEmpty(cameraMap) && cameraMap.containsKey(vidInfo.getLastCameraId())) {
                        Camera camera = cameraMap.get(vidInfo.getLastCameraId());
                        vidInfo.setCameraName(camera.getName());
                        vidInfo.setLon(camera.getLon());
                        vidInfo.setLat(camera.getLat());
                    }
                    model.setVidInfo(vidInfo);
                    if (!CollectionUtils.isEmpty(peopleList)) {
                        for (People people : peopleList) {
                            if (StringUtils.isEmpty(vidInfo.getIdCard()) || StringUtils.isEmpty(people.getCredentialNo())) {
                                continue;
                            }
                            //根据身份证来关联实有人口信息，解决一人聚类成多个vid的情况。
                            if (vidInfo.getIdCard().trim().equals(people.getCredentialNo().trim())) {
                                Long lastTime = vidInfo.getLastLogTime();
                                if (lastTime != null) {
                                    int day = DateUtils.getDateDaySpace(new Date(), new Date(lastTime));
                                    people.setLastDay(day);
                                }
                                model.setPeople(people);
                            }
                        }
                    }
                    listModel.add(model);
                }
            }
        }
        return listModel;
    }

    private VidInfo bulidVidInfo(Map<String, Object> map) {
        if (map != null && map.size() > 0) {
            VidInfo vidInfo = new VidInfo();
            for (String key : map.keySet()) {
                eSRestUtils.setFieldValueByFieldName(key, vidInfo, map.get(key));
            }
            return vidInfo;
        }
        return null;
    }

    public List<Map<String, Object>> getUpdateTimeByVid(List<String> vidList) {
        try {
            String[] indexs = new String[]{EsIndex.VIDINFO};
//            List<Map<String, Object>> results = eSRestUtils.getDataById(indexs, vidList);
            return eSRestUtils.getDataById(indexs, vidList);
        } catch (Exception e) {
            log.error("视屏档案查询错误", e);
        }
        return new ArrayList<>();
    }

    public Long getUpdateTimeByVid(String vid) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (vid != null && !"".equals(vid)) {
            boolQueryBuilder.must(QueryBuilders.termsQuery("vid", vid));
        }
        try {
            String[] indexs = new String[]{EsIndex.VIDINFO};
            List<Map<String, Object>> data = eSRestUtils.getDataById(indexs, vid);
            if (data != null && data.size() > 0) {
                Map<String, Object> map = data.get(0);
                return map.get("lastLogTime") == null ? null : Long.parseLong(String.valueOf(map.get("lastLogTime")));
            }
        } catch (Exception e) {
            log.error("视屏档案查询错误");
        }
        return null;
    }

    private BoolQueryBuilder getBoolQueryBuilder(SearchModel searchModel) {
        return getBoolQueryBuilder(searchModel, getMustQueryBuilder(searchModel));
    }

    private BoolQueryBuilder getBoolQueryBuilder(SearchModel searchModel,BoolQueryBuilder mustQueryBuilder) {
        if (searchModel.getIsConnect() != null) {
            if (!searchModel.getIsConnect()) {
                BoolQueryBuilder shouldQueryBuilder = QueryBuilders.boolQuery();
                shouldQueryBuilder.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("idCard")).must(mustQueryBuilder))
                        .should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("idCard.keyword", "")).must(mustQueryBuilder));
                return shouldQueryBuilder;
            } else {
                mustQueryBuilder.must(QueryBuilders.existsQuery("idCard"));
                mustQueryBuilder.mustNot(QueryBuilders.termQuery("idCard.keyword", ""));
                return mustQueryBuilder;
            }
        } else {
            return mustQueryBuilder;
        }
    }

    private BoolQueryBuilder getMustQueryBuilder(SearchModel searchModel) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (searchModel.getVid() != null && searchModel.getVid().length > 0) {
            boolQueryBuilder.must(QueryBuilders.termsQuery("vid", searchModel.getVid()));
        }

        if (searchModel.getMinCount() > 0) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("freq").gte(searchModel.getMinCount()));
        }

        if (searchModel.getMaxCount() > 0) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("freq").lt(searchModel.getMaxCount()));
        }

        if (searchModel.getStartDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("lastLogTime").gte(searchModel.getStartDate().getTime()));
        }

        if (searchModel.getEndDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("lastLogTime").lt(searchModel.getEndDate().getTime()));
        }

        if (searchModel.getVillageCode() != null && !"".equals(searchModel.getVillageCode())) {
            boolQueryBuilder.must(QueryBuilders.termsQuery("communityId", searchModel.getVillageCode().split(",")));
        }

        return boolQueryBuilder;
    }
}
